package constructor;

import ga.BotoxGA;
import ga.BotoxGA.Bloque;
import ga.BotoxGA.Campo;
import ga.BotoxGA.Campos;
import ga.BotoxGA.Caso;
import ga.BotoxGA.Casos;
import ga.BotoxGA.Declaracion;
import ga.BotoxGA.Declaraciones;
import ga.BotoxGA.Exp0;
import ga.BotoxGA.Exp1;
import ga.BotoxGA.Exp2;
import ga.BotoxGA.Exp3;
import ga.BotoxGA.Exp4;
import ga.BotoxGA.IAsignacion;
import ga.BotoxGA.IDispose;
import ga.BotoxGA.IDo;
import ga.BotoxGA.IIf;
import ga.BotoxGA.ILlamada;
import ga.BotoxGA.INew;
import ga.BotoxGA.IRead;
import ga.BotoxGA.IWrite;
import ga.BotoxGA.Instruccion;
import ga.BotoxGA.Instrucciones;
import ga.BotoxGA.ListaParametrosFormales;
import ga.BotoxGA.ListaParametrosReales;
import ga.BotoxGA.Mem;
import ga.BotoxGA.OpAditivo;
import ga.BotoxGA.OpComparacion;
import ga.BotoxGA.OpMultiplicativo;
import ga.BotoxGA.OpUnario;
import ga.BotoxGA.ParametroFormal;
import ga.BotoxGA.ParametrosFormales;
import ga.BotoxGA.ParametrosReales;
import ga.BotoxGA.Programa;
import ga.BotoxGA.Tipo;

import java.io.IOException;

import lexico.AnalizadorLexico;
import lexico.CatLexica;
import utils.Token;

public class ConstructorArbolesBotox {
	private Token tact;
	private AnalizadorLexico analizadorLexico;
	private BotoxGA gramaticaAtributos = new BotoxGA();
	private static final boolean DEBUG = true;

	public ConstructorArbolesBotox(AnalizadorLexico analizadorLexico) {
		this.analizadorLexico = analizadorLexico;
	}

	public Programa parse() throws IOException {
		tact = analizadorLexico.nextToken();
		Programa aPrograma = recPrograma();
		rec(CatLexica.EOF);
		return aPrograma;
	}

	// -------------------------------------------------
	// GRAMATICA
	// -------------------------------------------------

	private Programa recPrograma() throws IOException {
		/**
		 *	Programa ::= Bloque
		 *		Programa.a = programaR1(Bloque.a)
		 */
		return programaR1(recBloque());
	}

	private Bloque recBloque() throws IOException {
		/**											
		 * Bloque ::= int IDEN RDeclaraciones & Instrucciones
		 * Bloque ::= boolean IDEN RDeclaraciones & Instrucciones
		 * Bloque ::= array [NUM] of Tipo IDEN RDeclaraciones & Instrucciones
		 * Bloque ::= record { Campos } IDEN RDecs & Insts
		 * Bloque ::= ^ Tipo IDEN RDeclaraciones & Instrucciones
		 * Bloque ::= IDEN RBloque
		 * Bloque ::= type Tipo IDEN RDeclaraciones & Instrucciones
		 * Bloque ::= proc IDEN ( ParamsFormales ) { Bloque } RDeclaraciones & Instrucciones
		 * Bloque ::= INew RInstrucciones
		 * Bloque ::= IDispose RInstrucciones
		 * Bloque ::= IRead RInstrucciones
		 * Bloque ::= IWrite RInstrucciones
		 * Bloque ::= IIf RInstrucciones
		 * Bloque ::= IDo RInstrucciones
		 */
		if (tokenActual(CatLexica.INT, CatLexica.BOOLEAN, CatLexica.ARRAY, CatLexica.RECORD, CatLexica.PUNTERO)) {
			/*
			 * Bloque ::= int IDEN RDeclaraciones & Instrucciones
			 * Bloque ::= boolean IDEN RDeclaraciones & Instrucciones
			 * Bloque ::= array [NUM] of Tipo IDEN RDeclaraciones & Instrucciones
			 * Bloque ::= record { Campos } IDEN RDecs & Insts
			 * Bloque ::= ^ Tipo IDEN RDeclaraciones & Instrucciones
			 */
			return recIdenParaBloque(recTipo(), 1);
		}  else if (tokenActual(CatLexica.TYPE)) {
			/*
			 * Bloque ::= type Tipo IDEN RDeclaraciones & Instrucciones
			 */
			rec(CatLexica.TYPE);
			return recIdenParaBloque(recTipo(), 2);
		} else if (tokenActual(CatLexica.PROC)) {
			/*
			 * Bloque ::= proc IDEN ( ParamsFormales ) { Bloque } RDeclaraciones & Instrucciones
			 */
			rec(CatLexica.PROC);
			if (tokenActual(CatLexica.IDEN)) {
				Token tIden = tact;
				rec(CatLexica.IDEN);
				if (tokenActual(CatLexica.PA)) {
					rec(CatLexica.PA);
					ParametrosFormales pF = recParametrosFormales();
					if (tokenActual(CatLexica.PC)) {
						rec(CatLexica.PC);
						if (tokenActual(CatLexica.LLA)) {
							rec(CatLexica.LLA);
							Bloque bloque = recBloque();
							if (tokenActual(CatLexica.LLC)) {
								rec(CatLexica.LLC);
								Declaraciones decs = recRDeclaraciones(decsR2(decR3(tIden, pF, bloque)));
								if (tokenActual(CatLexica.APS)) {
									rec(CatLexica.APS);
									return bloqueR1(decs, recInstrucciones());
								} else {
									errorSintactico(CatLexica.APS);
									return null;
								}
							} else {
								errorSintactico(CatLexica.LLC);
								return null;
							}
						} else {
							errorSintactico(CatLexica.LLA);
							return null;
						}
					} else {
						errorSintactico(CatLexica.PC);
						return null;
					}
				} else {
					errorSintactico(CatLexica.PA);
					return null;
				}
			} else {
				errorSintactico(CatLexica.IDEN);
				return null;
			}
		} else if (tokenActual(CatLexica.IDEN)) {
			/*
			 * Bloque ::= IDEN RBloque
			 */
			Token tIden = tact;
			rec(CatLexica.IDEN);
			return recRBloque(tIden);
		} else if (tokenActual(CatLexica.NEW)) {
			/*
			 * Bloque ::= INew RInstrucciones
			 */
			rec(CatLexica.NEW);
			return bloqueR2(recRInstrucciones(instsR2(instR2(recINew()))));
		} else if (tokenActual(CatLexica.DISPOSE)) {
			/*
			 * Bloque ::= IDispose RInstrucciones
			 */
			rec(CatLexica.DISPOSE);
			return bloqueR2(recRInstrucciones(instsR2(instR3(recIDispose()))));
		} else if (tokenActual(CatLexica.READ)) {
			/*
			 * Bloque ::= IRead RInstrucciones
			 */
			rec(CatLexica.READ);
			return bloqueR2(recRInstrucciones(instsR2(instR4(recIRead()))));
		} else if (tokenActual(CatLexica.WRITE)) {
			 /*
			  * Bloque ::= IWrite RInstrucciones
			  */
			rec(CatLexica.WRITE);
			return bloqueR2(recRInstrucciones(instsR2(instR5(recIWrite()))));
		} else if (tokenActual(CatLexica.IF)) {
			/*
			 * Bloque ::= IIf RInstrucciones
			 */
			rec(CatLexica.IF);
			return bloqueR2(recRInstrucciones(instsR2(instR7(recIIf()))));
		} else if (tokenActual(CatLexica.DO)) {
			/*
			 * Bloque ::= IDo RInstrucciones
			 */
			rec(CatLexica.DO);
			return bloqueR2(recRInstrucciones(instsR2(instR8(recIDo()))));
		} else {
			errorSintactico(CatLexica.INT, CatLexica.BOOLEAN, CatLexica.ARRAY,
					CatLexica.RECORD, CatLexica.PUNTERO, CatLexica.IDEN,
					CatLexica.TYPE, CatLexica.PROC, CatLexica.NEW,
					CatLexica.DISPOSE, CatLexica.READ, CatLexica.WRITE,
					CatLexica.IF, CatLexica.DO);
			return null;
		}
	}

	private Bloque recRBloque(Token iden) throws IOException {
		/**
		 * RBloque ::= IDEN RDeclaraciones & Instrucciones
		 * RBloque ::= RInstruccion RInstrucciones
		 */
		if (tokenActual(CatLexica.IDEN)) {
			/*
			 * RBloque ::= IDEN RDeclaraciones & Instrucciones
			 */
			Token tIden = tact;
			rec(CatLexica.IDEN);
			Declaraciones decs = recRDeclaraciones(decsR2(decR1(tipoR6(iden), tIden)));
			if (tokenActual(CatLexica.APS)) {
				return bloqueR1(decs, recInstrucciones());
			} else {
				errorSintactico(CatLexica.APS);
				return null;
			}
		} else {
			/*
			 * RBloque ::= RInstruccion RInstrucciones
			 */
			return bloqueR2(recRInstrucciones(instsR2(recRInstruccion(iden))));
		}
	}

	private Declaraciones recRDeclaraciones(Declaraciones ahRDeclaraciones) throws IOException {
		/**
		 *	RDeclaraciones ::= ; Declaracion RDeclaraciones
		 *		RDeclaraciones(1).ah = DeclaracionesR1(Declaracion.a, RDeclaraciones(0).ah)
		 *		RDeclaraciones(0).a = RDeclaraciones(1).a
		 *
		 *	RDeclaraciones ::= vacio
		 *		RDeclaraciones.a = RDeclaraciones.ah
		 */
		if (tokenActual(CatLexica.PyC)) {
			/*
			 * RDeclaraciones ::= ; Declaracion RDeclaraciones
			 */
			rec(CatLexica.PyC);
			return recRDeclaraciones(decsR1(ahRDeclaraciones, recDeclaracion()));
		} else {
			/*
			 * RDeclaraciones ::= vacio
			 */
			return ahRDeclaraciones;
		}
	}

	private Declaracion recDeclaracion() throws IOException {
		/**
		 *	Declaracion ::= int IDEN
		 *		Declaracion.a = declaracionR1(tipoR1(), IDEN.lex)
		 *
		 *	Declaracion ::= boolean IDEN
		 *		Declaracion.a = declaracionR1(tipoR2(), IDEN.lex)
		 *
		 *	Declaracion ::= array [NUM] of Tipo IDEN
		 *		Declaracion.a = declaracionR1(tipoR3(NUM.lex, Tipo.a), IDEN.lex)
		 *
		 *	Declaracion ::= record { Campos } IDEN
		 *		Declaracion.a = declaracionR1(tipoR4(Campos.a), IDEN.lex)
		 *
		 *	Declaracion ::= ^ Tipo IDEN
		 *		Declaracion.a = declaracionR1(tipoR5(Tipo.a), IDEN.lex)
		 *
		 *	Declaracion ::= IDEN IDEN
		 *		Declaracion.a = declaracionR1(tipoR6(IDEN(0).lex), IDEN(1).lex)
		 *
		 *	Declaracion ::= type Tipo IDEN
		 *		Declaracion.a = declaracionR2(Tipo.a, IDEN.lex)
		 *
		 *	Declaracion ::= proc IDEN ( ParametrosFormales ) { Bloque }
		 *		Declaracion.a = declaracionR3(IDEN.lex, ParametrosFormales.a, Bloque.a)
		 */
		if (tokenActual(CatLexica.INT, CatLexica.BOOLEAN, CatLexica.ARRAY, CatLexica.RECORD, CatLexica.PUNTERO, CatLexica.IDEN)) {
			/*
			 * Declaracion ::= int IDEN
			 * Declaracion ::= boolean IDEN
			 * Declaracion ::= array [NUM] of Tipo IDEN
			 * Declaracion ::= record { Campos } IDEN
			 * Declaracion ::= IDEN IDEN
			 */
			return recIdenParaDeclaracion(recTipo(), 1);
		} else if (tokenActual(CatLexica.TYPE)) {
			/*
			 * Declaracion ::= type Tipo IDEN
			 */
			rec(CatLexica.TYPE);
			return recIdenParaDeclaracion(recTipo(), 2);
		} else if (tokenActual(CatLexica.PROC)) {
			/*
			 * Declaracion ::= proc IDEN ( ParametrosFormales ) { Bloque }
			 */
			rec(CatLexica.PROC);
			if (tokenActual(CatLexica.IDEN)) { 
				Token tIden = tact;
				rec(CatLexica.IDEN);
				if (tokenActual(CatLexica.PA)) { 
					rec(CatLexica.PA);
					ParametrosFormales pF = recParametrosFormales();
					if (tokenActual(CatLexica.CC)) { 
						rec(CatLexica.CC);
						if (tokenActual(CatLexica.LLA)) { 
							rec(CatLexica.LLA);
							Bloque bloque = recBloque();
							if (tokenActual(CatLexica.LLC)) {
								rec(CatLexica.LLC);
								return decR3(tIden, pF, bloque);
							}
						}
					}
				}
			}
		}
		errorSintactico(CatLexica.INT, CatLexica.BOOLEAN, CatLexica.ARRAY,
				CatLexica.CA, CatLexica.NUM, CatLexica.CC, CatLexica.OF,
				CatLexica.RECORD, CatLexica.LLA, CatLexica.LLC,
				CatLexica.PUNTERO, CatLexica.IDEN, CatLexica.TYPE,
				CatLexica.PROC, CatLexica.PA, CatLexica.PC);
		return null;
	}

	private ParametrosFormales recParametrosFormales()
			throws IOException {
		/**
		 *	ParametrosFormales ::= ListaParametrosFormales
		 *		ParametrosFormales.a = parametrosFormalesR1(ListaParametrosFormales.a)
		 * 
		 *	ParametrosFormales ::= vacio
		 *		ParametrosFormales.a = ParametrosFormales.ah
		 */
		if (tokenActual(CatLexica.INT, CatLexica.BOOLEAN, CatLexica.ARRAY,
				CatLexica.RECORD, CatLexica.PUNTERO, CatLexica.IDEN,
				CatLexica.VAR)) {
			/*
			 * ParametrosFormales ::= ListaParametrosFormales
			 */
			return pFormalesR1(recListaParametrosFormales());
		} else {
			/*
			 * ParametrosFormales ::= vacio
			 */
			return pFormalesR2();
		}
	}

	private ListaParametrosFormales recListaParametrosFormales()
			throws IOException {
		/**
		 *	ListaParametrosFormales ::= ParametroFormal RListaParametrosFormales
		 *		ListaParametrosFormales.a = RListaParametrosFormales.a
		 *		RListaParametrosFormales.ah = listaParametrosFormalesR2(ParametroFormal.a)
		 */
		return recRListaParametrosFormales(lPFormalesR2(recParametroFormal()));
	}

	private ListaParametrosFormales recRListaParametrosFormales(
			ListaParametrosFormales ahRListaParametrosFormales)
			throws IOException {
		/**
		 *	RListaParametrosFormales ::= , ParametroFormal RListaParametrosFormales
		 *		RListaParametrosFormales(1).ah = listaParametrosFormalesR1(ParametroFormal.a, RListaParametrosFormales(0).ah)
		 *		RListaParametrosFormales(0).a = RListaParametrosFormales(1).a
		 * 
		 *	RListaParametrosFormales ::= vacio
		 *		RListaParametrosFormales.a = RListaParametrosFormales.ah
		 */
		if (tokenActual(CatLexica.COMA)) {
			/*
			 * RListaParametrosFormales ::= , ParametroFormal RListaParametrosFormales
			 */
			rec(CatLexica.COMA);
			return recRListaParametrosFormales(lPFormalesR1(recParametroFormal(), ahRListaParametrosFormales));
		} else {
			/*
			 * RListaParametrosFormales ::= vacio
			 */
			return ahRListaParametrosFormales;
		}
	}

	private ParametroFormal recParametroFormal() throws IOException {
		/**
		 *	ParametroFormal ::= Tipo IDEN
		 *		ParametroFormal.a = parametroFormalR1(Tipo.a, IDEN.lex)
		 * 
		 *	ParametroFormal ::= var Tipo IDEN
		 *		ParametroFormal.a = parametroFormalR2(Tipo.a, IDEN.lex)
		 */
		if (tokenActual(CatLexica.VAR)) {
			/*
			 * ParametroFormal ::= var Tipo IDEN
			 */
			rec(CatLexica.VAR);
			return recIdenParaParamFormal(recTipo(), 2);
		} else {
			/*
			 * ParametroFormal ::= Tipo IDEN
			 */
			return recIdenParaParamFormal(recTipo(), 1);
		}
	}

	private Tipo recTipo() throws IOException {
		/**
		 *	Tipo ::= int
		 * 		Tipo.a = tipoR1()
		 * 
		 *	Tipo ::= boolean
		 *		Tipo.a = tipoR2()
		 * 
		 *	Tipo ::= array [NUM] of Tipo
		 *		Tipo(0).a = tipoR3(NUM.lex, Tipo.a)
		 * 
		 *	Tipo ::= record { Campos }
		 *		Tipo.a = tipoR4(Campos.a)
		 * 
		 *	Tipo ::= ^ Tipo
		 *		Tipo(0).a = tipoR5(Tipo(1).a)
		 * 
		 *	Tipo ::= IDEN
		 *		Tipo.a = tipoR6(IDEN.lex)
		 */
		if (tokenActual(CatLexica.INT)) {
			/*
			 * Tipo ::= int
			 */
			rec(CatLexica.INT);
			return tipoR1();
		} else if (tokenActual(CatLexica.BOOLEAN)) {
			/*
			 * Tipo ::= boolean
			 */
			rec(CatLexica.BOOLEAN);
			return tipoR2();
		} else if (tokenActual(CatLexica.ARRAY)) {
			/*
			 * Tipo ::= array [NUM] of Tipo
			 */
			rec(CatLexica.ARRAY);
			if (tokenActual(CatLexica.CA)) {
				rec(CatLexica.CA);
				if (tokenActual(CatLexica.NUM)) { 
					Token tNum = tact;
					rec(CatLexica.NUM);
					if (tokenActual(CatLexica.CC)) {
						rec(CatLexica.CC);
						if (tokenActual(CatLexica.OF)) {
							rec(CatLexica.OF);
							return tipoR3(recTipo(), tNum);
						}
					}
				}
			}
		} else if (tokenActual(CatLexica.RECORD)) {
			/*
			 * Tipo ::= record { Campos }
			 */
			rec(CatLexica.RECORD);
			if (tokenActual(CatLexica.LLA)) {
				rec(CatLexica.LLA);
				Campos campos = recCampos();
				if (tokenActual(CatLexica.LLC)) {
					rec(CatLexica.LLC);
					return tipoR4(campos);
				}
			}
		} else if (tokenActual(CatLexica.PUNTERO)) {
			/*
			 * Tipo ::= ^ Tipo
			 */
			rec(CatLexica.PUNTERO);
			return tipoR5(recTipo());
		} else if (tokenActual(CatLexica.IDEN)) {
			/*
			 * Tipo ::= IDEN
			 */
			Token tIden = tact;
			rec(CatLexica.IDEN);
			return tipoR6(tIden);
		}
		errorSintactico(CatLexica.INT, CatLexica.BOOLEAN, CatLexica.ARRAY,
				CatLexica.CA, CatLexica.NUM, CatLexica.CC, CatLexica.OF,
				CatLexica.RECORD, CatLexica.LLA, CatLexica.LLC,
				CatLexica.PUNTERO, CatLexica.IDEN);
		return null;
	}

	private Campos recCampos() throws IOException {
		/**
		 *	Campos ::= Campo RCampos
		 *		Campos.a = RCampos.a
		 *		Campos.ah = camposR2(Campo.a)
		 */
		return recRCampos(camposR2(recCampo()));
	}

	private Campos recRCampos(Campos ahRCampos) throws IOException {
		/**
		 *	RCampos ::= ; Campo RCampos
		 *		RCampos(1).ah = camposR1(Campo.a, RCampos(0).ah)
		 *		RCampos(0).a = RCampos(1).a
		 *
		 *	RCampos ::= vacio
		 *		RCampos.a = RCampos.ah
		 */
		if (tokenActual(CatLexica.PyC)) {
			/*
			 * RCampos ::= ; Campo RCampos
			 */
			rec(CatLexica.PyC);
			return recRCampos(camposR1(ahRCampos, recCampo()));
		} else {
			/*
			 * RCampos ::= vacio
			 */
			return ahRCampos;
		}
	}

	private Campo recCampo() throws IOException {
		/**
		 *	Campo ::= Tipo IDEN
		 *		Campo.a = campoR1(Tipo.a, IDEN.lex)
		 */
		Tipo tipo = recTipo();
		if (tokenActual(CatLexica.IDEN)) {
			Token tIden = tact;
			rec(CatLexica.IDEN);
			return campoR1(tipo, tIden);
		}
		errorSintactico(CatLexica.IDEN);
		return null;
	}

	private Instrucciones recInstrucciones() throws IOException {
		/**
		 * Instrucciones ::= IDEN RInstruccion RInstrucciones
		 * 		Instrucciones.a = RInstrucciones.a
		 * 		RInstrucciones.ah = instruccionesR2(RI.a)
		 * 		RInstruccion.ah = IDEN.lex
		 * 
		 * Instrucciones ::= INew RInstrucciones
		 * 		Instrucciones.a = RInstrucciones.a
		 * 		RInstrucciones.ah = instruccionesR2(instruccionR2(INew.a))
		 * 
		 * Instrucciones ::= IDispose RInstrucciones
		 * 		Instrucciones.a = RInstrucciones.a
		 * 		RInstrucciones.ah = instruccionR3(IDispose.a)
		 * 
		 * Instrucciones ::= IRead RInstrucciones
		 * 		Instrucciones.a = RInstrucciones.a
		 * 		RInstrucciones.ah = instruccionR4(IRead.a)
		 * 
		 * Instrucciones ::= IWrite RInstrucciones
		 * 		Instrucciones.a = RInstrucciones.a
		 * 		RInstrucciones.ah = instruccionR5(IWrite.a)
		 * 
		 * Instrucciones ::= IIF RInstrucciones
		 * 		Instrucciones.a = RInstrucciones.a
		 * 		RInstrucciones.ah = instruccionR7(IIF.a)
		 * 
		 * Instrucciones ::= IDO RInstrucciones
		 * 		Instrucciones.a = RInstrucciones.a
		 * 		RInstrucciones.ah = instruccionR8(IDO.a)
		 */
		if (tokenActual(CatLexica.IDEN)) {
			/*
			 * Instrucciones ::= IDEN RInstruccion RInstrucciones
			 */
			Token tIden = tact;
			rec(CatLexica.IDEN);
			return recRInstrucciones(instsR2(recRInstruccion(tIden)));
		} else if (tokenActual(CatLexica.NEW)) {
			/*
			 * Instrucciones ::= INew RInstrucciones
			 */
			return recRInstrucciones(instsR2(instR2(recINew())));
		} else if (tokenActual(CatLexica.DISPOSE)) {
			/*
			 * Instrucciones ::= IDispose RInstrucciones
			 */
			return recRInstrucciones(instsR2(instR3(recIDispose())));
		} else if (tokenActual(CatLexica.READ)) {
			/*
			 * Instrucciones ::= IRead RInstrucciones
			 */
			return recRInstrucciones(instsR2(instR4(recIRead())));
		} else if (tokenActual(CatLexica.WRITE)) {
			/*
			 * Instrucciones ::= IWrite RInstrucciones
			 */
			return recRInstrucciones(instsR2(instR5(recIWrite())));
		} else if (tokenActual(CatLexica.IF)) {
			/*
			 * Instrucciones ::= IIF RInstrucciones
			 */
			return recRInstrucciones(instsR2(instR7(recIIf())));
		} else if (tokenActual(CatLexica.DO)) {
			/*
			 * Instrucciones ::= IDO RInstrucciones
			 */
			return recRInstrucciones(instsR2(instR8(recIDo())));
		}
		errorSintactico(CatLexica.IDEN, CatLexica.NEW, CatLexica.DISPOSE,
				CatLexica.READ, CatLexica.WRITE, CatLexica.IF, CatLexica.DO);
		return null;
	}

	private Instrucciones recRInstrucciones(Instrucciones ahRInstrucciones) throws IOException {
		/**
		 *	RInstrucciones ::= ; Instruccion RInstrucciones
		 *		RInstrucciones(1).ah = instruccionesR1(Instruccion.a, RInstrucciones(0).ah)
		 *		RInstrucciones(0).a  = RInstrucciones(1).a
		 *
		 *	RInstrucciones ::= vacio
		 *		RInstrucciones.a = RInstrucciones.ah
		 */
		if (tokenActual(CatLexica.PyC)) {
			/*
			 * RInstrucciones ::= ; Instruccion RInstrucciones
			 */
			rec(CatLexica.PyC);
			return recRInstrucciones(instsR1(ahRInstrucciones, recInstruccion()));
		} else {
			/*
			 * RInstrucciones ::= vacio
			 */
			return ahRInstrucciones;
		}
	}

	private Instruccion recInstruccion() throws IOException {
		/**
		 *	Instruccion ::= IDEN RInstruccion
		 *		Instruccion.a = RInstruccion.a
		 *		RInstruccion.ah = IDEN.lex
		 * 
		 *	Instruccion ::= INew
		 *		Instruccion.a = instruccionR2(INew.a)
		 *
		 *	Instruccion ::= IDispose
		 *		Instruccion.a = instruccionR3(IDispose.a)
		 *
		 *	Instruccion ::= IRead
		 *		Instruccion.a = instruccionR4(IRead.a)
		 *
		 *	Instruccion ::= IWrite
		 *		Instruccion.a = instruccionR5(IWrite.a)
		 *
		 *	Instruccion ::= IIf
		 *		Intruccion.a = instruccionR7(IIF.a)
		 *
		 *	Instruccion ::= IDo
		 *		Instruccion.a = instruccionR8(IDO.a)
		 */
		if (tokenActual(CatLexica.IDEN)) {
			/*
			 * Instruccion ::= IDEN RInstruccion
			 */
			Token tIden = tact;
			rec(CatLexica.IDEN);
			return recRInstruccion(tIden);
		} else if (tokenActual(CatLexica.NEW)) {
			/*
			 * Instruccion ::= INew
			 */
			return instR2(recINew());
		} else if (tokenActual(CatLexica.DISPOSE)) {
			/*
			 * Instruccion ::= IDispose
			 */
			return instR3(recIDispose());
		} else if (tokenActual(CatLexica.READ)) {
			/*
			 * Instruccion ::= IRead
			 */
			return instR4(recIRead());
		} else if (tokenActual(CatLexica.WRITE)) {
			/*
			 * Instruccion ::= IWrite
			 */
			return instR5(recIWrite());
		} else if (tokenActual(CatLexica.IF)) {
			/*
			 * Instruccion ::= IIf
			 */
			return instR7(recIIf());
		} else if (tokenActual(CatLexica.DO)) {
			/*
			 * Instruccion ::= IDo
			 */
			return instR8(recIDo());
		}
		errorSintactico(CatLexica.IDEN, CatLexica.NEW, CatLexica.DISPOSE,
				CatLexica.READ, CatLexica.WRITE, CatLexica.DO, CatLexica.IF);
		return null;
	}
	
	private Instruccion recRInstruccion(Token iden) throws IOException {
		/**
		 * RInst ::= RMem := Exp0
		 * RInst ::= ( ParamsReales )
		 */
		if (tokenActual(CatLexica.PA)) {
			/*
			 * RInst ::= ( ParamsReales )
			 */
			return instR6(recILlamada(iden));
		} else {
			/*
			 * RInst ::= RMem := Exp0
			 */
			return instR1(recIAsignacion(iden));
		}
	}

	private IAsignacion recIAsignacion(Token iden) throws IOException {
		/**
		 *	IAsignacion ::= Mem := Exp0
		 *		IAsignacion.a = iAsignacionR1(Mem.a, Exp0.a)
		 */
		Mem mem = recRMem(memR1(iden));
		if (tokenActual(CatLexica.ASIG)) {
			rec(CatLexica.ASIG);
			return iAsignacionR1(mem, recExp0());
		}
		errorSintactico(CatLexica.ASIG);
		return null;
	}
	
	private INew recINew() throws IOException {
		/**
		 *	INew ::= new Mem
		 *		INew.a = iNewR1(Mem.a)
		 */
		rec(CatLexica.NEW);
		return iNewR1(recMem());
	}

	private IDispose recIDispose() throws IOException {
		/**
		 *	IDispose ::= delete Mem
		 *		IDispose.a = iDisposeR1(Mem.a)
		 */
		rec(CatLexica.DISPOSE);
		return iDisposeR1(recMem());
	}

	private IRead recIRead() throws IOException {
		/**
		 *	IRead ::= read Mem
		 *		IRead.a = iReadR1(Mem.a)	
		 */
		rec(CatLexica.READ);
		return iReadR1(recMem());
	}

	private IWrite recIWrite() throws IOException {
		/**
		 *	IWrite ::= write Exp0
		 *		IWrite.a = iWriteR1(Exp0.a)
		 */
		rec(CatLexica.WRITE);
		return iWriteR1(recExp0());
	}
	
	private ILlamada recILlamada(Token iden) throws IOException {
		/**
		 * ILlamada ::= IDEN ( ParamsReales )
		 */
		rec(CatLexica.PA);
		ParametrosReales pR = recParametrosReales();
		if (tokenActual(CatLexica.PC)) {
			rec(CatLexica.PC);
			return iLlamadaR1(iden, pR);
		}
		errorSintactico(CatLexica.PC);
		return null;
	}

	private IIf recIIf() throws IOException {
		/**
		 *	IIF ::= if Casos fi
		 *		IIF.a = iIfR1(Casos.a)
		 */
		rec(CatLexica.IF);
		Casos casos = recCasos();
		rec(CatLexica.FI);
		return iIfR1(casos);
	}

	private IDo recIDo() throws IOException {
		/**
		 *	IDO ::= do Casos od
		 *		IDO.a = iDoR1(Casos.a)
		 */
		rec(CatLexica.DO);
		Casos casos = recCasos();
		rec(CatLexica.OD);
		return iDoR1(casos);
	}

	private Casos recCasos() throws IOException {
		/**
		 *	Casos ::= Caso RCasos
		 *		RCasos.ah = casosR2(Caso.a)
		 *		Casos.a = RCasos.a
		 */
		return recRCasos(casosR2(recCaso()));
	}

	private Casos recRCasos(Casos ahRCasos) throws IOException {
		/**
		 *	RCasos ::= [] Caso RCasos
		 *		RCasos(1).ah = casosR1(RCasos(0).ah, Caso.a)
		 *		RCasos(0).a = RCasos(1).a
		 *
		 *	RCasos ::= vacio
		 *		RCasos.a = RCaso.ah
		 */
		if (tokenActual(CatLexica.C)) {
			/*
			 * RCasos ::= [] Caso RCasos
			 */
			rec(CatLexica.C);
			return recRCasos(casosR1(ahRCasos, recCaso()));
		} else {
			/*
			 * RCasos ::= vacio
			 */
			return ahRCasos;
		}
	}

	private Caso recCaso() throws IOException {
		/**
		 *	Caso ::= case Exp0 -> Instrucciones
		 *		Caso.a = casoR1(Exp0.a, Instrucciones.a)
		 */
		if (tokenActual(CatLexica.CASE)) { 
			rec(CatLexica.CASE);
			Exp0 exp = recExp0();
			if (tokenActual(CatLexica.IMPL)) {
				rec(CatLexica.IMPL);
				return casoR1(exp, recInstrucciones());
			}
		}
		errorSintactico(CatLexica.CASE, CatLexica.IMPL);
		return null;
	}

	private ParametrosReales recParametrosReales() throws IOException {
		/**
		 *	ParametrosReales ::= ListaParametrosReales
		 * 		ParametrosReales.a = parametrosRealesR1(ListaParametrosReales.a)
		 * 
		 *	ParametrosReales ::= vacio
		 * 		ParametrosReales.a = Parametros
		 */
		if (tokenActual(CatLexica.IDEN, CatLexica.NUM, CatLexica.MENOS,
				CatLexica.NOT, CatLexica.TRUE, CatLexica.FALSE, CatLexica.PA)) {
			/*
			 * ParametrosReales ::= ListaParametrosReales
			 */
			if (tokenActual(CatLexica.IDEN)) {
				rec(CatLexica.IDEN);
			} else if (tokenActual(CatLexica.NUM)) {
				rec(CatLexica.NUM);
			} else if (tokenActual(CatLexica.MENOS)) {
				rec(CatLexica.MENOS);
			} else if (tokenActual(CatLexica.NOT)) {
				rec(CatLexica.NOT);
			} else if (tokenActual(CatLexica.TRUE)) {
				rec(CatLexica.TRUE);
			} else if (tokenActual(CatLexica.FALSE)) {
				rec(CatLexica.FALSE);
			} else if (tokenActual(CatLexica.PA)) {
				rec(CatLexica.PA);
			}
			return pRealR1(recListaParametrosReales());
		} else if (tokenActual(CatLexica.PC)) {
			/*
			 * ParametrosReales ::= vacio
			 */
			rec(CatLexica.PC);
			return pRealR2();
		}
		errorSintactico(CatLexica.IDEN, CatLexica.NUM, CatLexica.MENOS,
				CatLexica.NOT, CatLexica.TRUE, CatLexica.FALSE, CatLexica.PA,
				CatLexica.PC);
		return null;
	}

	private ListaParametrosReales recListaParametrosReales() throws IOException {
		/**
		 *	ListaParametrosReales ::= Exp0 RListaParametrosReales
		 * 		ListaParametrosReales.a = RListaParametrosReales.a
		 * 		RListaParametrosReales.ah = listaParametrosRealesR2(Exp0.a)
		 */
		return recRListaParametrosReales(lPRealesR2(recExp0()));
	}

	private ListaParametrosReales recRListaParametrosReales(
			ListaParametrosReales ahRListaParametrosReales) throws IOException {
		/**
		 * RListaParametrosReales ::= , Exp0 RListaParametrosReales
		 * 		RListaParametrosReales(1).ah = listaParametrosRealesR1 (Exp0.a, RListaParametrosReales(0).ah)
		 * 		RListaParametrosReales(0).a = RListaParametrosReales(1).a
		 * 
		 * RListaParametrosReales ::= vacio
		 * 		RListaParametrosFormales.a = RListaParametrosFormales.ah
		 */
		if (tokenActual(CatLexica.COMA)) {
			/*
			 * RListaParametrosReales ::= , Exp0 RListaParametrosReales
			 */
			rec(CatLexica.COMA);
			return lPRealesR1(ahRListaParametrosReales, recExp0());
		} else {
			/*
			 * RListaParametrosReales ::= vacio
			 */
			return ahRListaParametrosReales;
		}
	}

	private Exp0 recExp0() throws IOException {
		/**
		 *	Exp0 := Exp1 RExp0
		 *		RExp0.ah = Exp1.a
		 *		Exp0.a = RExp0.a
		 */
		return recRExp0(recExp1());
	}

	private Exp0 recRExp0(Exp1 ahRExp0) throws IOException {
		/**
		 *	RExp0 ::= OpComparacion Exp1
		 *		RExp0(0).a = exp0R1(OpComparacion.a, Exp1.a, RExp0(0).ah)
		 *
		 *	RExp0 ::= vacio
		 *		RExp0.a = exp0R2(RExp0.ah)
		 */
		if (esOpComparacion()) {
			/*
			 * RExp0 ::= OpComparacion Exp1
			 */
			return exp0R1(recOpComparacion(), ahRExp0, recExp1());
		} else {
			/*
			 * RExp0 ::= vacio
			 */
			return exp0R2(ahRExp0);
		}
	}

	private Exp1 recExp1() throws IOException {
		/**
		 *	Exp1 ::= Exp2 RExp1
		 *		RExp1.ah = exp1R2(Exp2.a)
		 *		Exp1.a = RExp1.a
		 */
		return recRExp1(exp1R2(recExp2()));
	}

	private Exp1 recRExp1(Exp1 ahRExp1) throws IOException {
		/**
		 *	RExp1 ::= OpAditivo Exp2 RExp1
		 *		RExp1(1).ah = exp1R1(OpAditivo.a, Exp2.a, RExp1(0).ah)
		 *		RExp1(0).a = RExp1(1).a
		 *
		 *	RExp1 ::= vacio
		 *		RExp1.a = RExp1.ah
		 */
		if (esOpAditivo()) {
			/*
			 * RExp1 ::= OpAditivo Exp2 RExp1
			 */
			return recRExp1(exp1R1(recOpAditivo(), ahRExp1, recExp2()));
		} else {
			/*
			 * RExp1 ::= vacio
			 */
			return ahRExp1;
		}
	}

	private Exp2 recExp2() throws IOException {
		/**
		 *	Exp2 ::= Exp3 RExp2
		 *		RExp2.ah = exp2R2(Exp3.a)
		 *		Exp2.a = RExp2.a
		 */
		return recRExp2(exp2R2(recExp3()));
	}

	private Exp2 recRExp2(Exp2 ahRExp20) throws IOException {
		/**
		 *	RExp2 ::= OpMultiplicativo Exp3 RExp2
		 *		RExp2(1).ah = exp2R1(RExp2(0).ah, Exp3.a)
		 *		RExp2(0).a = RExp2(1).a
		 *
		 *	RExp2 ::= vacio
		 *		RExp2.a = RExp2.ah
		 */
		if (esOpMultiplicativo()) {
			/*
			 * RExp2 ::= OpMultiplicativo Exp3 RExp2
			 */
			return recRExp2(exp2R1(recOpMultiplicativo(), ahRExp20, recExp3()));
		} else {
			/*
			 * RExp2 ::= vacio
			 */
			return ahRExp20;
		}
	}

	private Exp3 recExp3() throws IOException {
		/**
		 *	Exp3 ::= OpUnario Exp3
		 *		Exp3(0).a = exp3R1(OpUnario.a, Exp3(1).a)
		 *
		 *	Exp3 ::= Exp4
		 *		Exp3.a = exp3R2(Exp4.a)
		 */
		if (esOpUnario()) {
			/*
			 * Exp3 ::= OpUnario Exp3
			 */
			return exp3R1(recOpUnario(), recExp3());
		} else {
			/*
			 * Exp3 ::= Exp4
			 */
			return exp3R2(recExp4());
		}
	}

	private Exp4 recExp4() throws IOException {
		/**
		 *	Exp4 ::= true
		 * 		Exp4.a = exp4R1(true)
		 * 
		 *	Exp4 ::= false
		 *		Exp4.a = exp4R2(false)
		 *
		 *	Exp4 ::= NUM
		 *		Exp4.a = exp4R3(Num.lex)
		 *
		 *	Exp4 ::= Mem
		 *		Exp4.a = exp4R4(Mem.a)
		 *
		 *	Exp4 ::= ( Exp0 )
		 *		Exp4.a = exp4R5(Exp0.a)
		 */
		if (tokenActual(CatLexica.TRUE)) {
			/*
			 * Exp4 ::= true
			 */
			Token tTrue = tact;
			rec(CatLexica.TRUE);
			return exp4R1(tTrue);
		} else if (tokenActual(CatLexica.FALSE)) {
			/*
			 * Exp4 ::= false
			 */
			Token tFalse = tact;
			rec(CatLexica.FALSE);
			return exp4R2(tFalse);
		} else if (tokenActual(CatLexica.NUM)) {
			/*
			 * Exp4 ::= NUM
			 */
			Token tNum = tact;
			rec(CatLexica.NUM);
			return exp4R3(tNum);
		} else if (tokenActual(CatLexica.IDEN)) {
			/*
			 * Exp4 ::= Mem
			 */
			return exp4R4(recMem());
		} else if (tokenActual(CatLexica.PA)) {
			/*
			 * Exp4 ::= ( Exp0 )
			 */
			rec(CatLexica.PA);
			Exp0 aExp0 = recExp0();
			if (tokenActual(CatLexica.PC)) {
				rec(CatLexica.PC);
				return exp4R5(aExp0);
			} else {
				errorSintactico(CatLexica.PC);
				return null;
			}
		} else {
			errorSintactico(CatLexica.TRUE, CatLexica.FALSE, CatLexica.NUM,
					CatLexica.IDEN, CatLexica.PA);
			return null;
		}
	}

	private Mem recMem() throws IOException {
		/**
		 *	Mem ::= IDEN RMem
		 *		Mem.a = RMem.a
		 *		RMem.ah = MemR1(IDEN.a)
		 */
		Token tIden = tact;
		rec(CatLexica.IDEN);
		return recRMem(memR1(tIden));
	}

	private Mem recRMem(Mem ahRMem) throws IOException {
		/**
		 *	RMem ::= [Exp0] RMem
		 *		RMem(1).ah = MemR2(Exp0.a, RMem(0).ah)
		 *		RMem(0).a = RMem(1).a
		 *
		 *	RMem ::= . IDEN RMem
		 *		RMem(1).ah = MemR3(IDEN.lex, RMem(0).ah)
		 *		RMem(0).a = RMem(1).a
		 *
		 *	RMem ::= ^ RMem
		 *		RMem(1).ah = MemR4(RMem(0).ah)
		 *		RMem(0).a = RMem(1).a
		 *
		 *	RMem ::= vacio
		 *		RMem.a = RMem.ah
		 */
		if (tokenActual(CatLexica.CA)) {
			/*
			 * RMem ::= [Exp0] RMem
			 */
			rec(CatLexica.CA);
			Exp0 exp = recExp0();
			if (tokenActual(CatLexica.CC)) {
				rec(CatLexica.CC);
				return recRMem(memR2(ahRMem, exp));
			} else {
				errorSintactico(CatLexica.CC);
				return null;
			}
		} else if (tokenActual(CatLexica.PUNTO)) {
			/*
			 * RMem ::= . IDEN RMem 
			 */
			rec(CatLexica.PUNTO);
			if (tokenActual(CatLexica.IDEN)) { 
				Token tIden = tact;
				rec(CatLexica.IDEN);
				return recRMem(memR3(ahRMem, tIden));
			} else {
				errorSintactico(CatLexica.IDEN);
				return null;
			}
		} else if (tokenActual(CatLexica.PUNTERO)) {
			/*
			 * RMem ::= ^ RMem
			 */
			rec(CatLexica.PUNTERO);
			return recRMem(memR4(ahRMem));
		} else {
			/*
			 * RMem ::= vacio
			 */
			return ahRMem;
		}
	}

	private OpComparacion recOpComparacion() throws IOException {
		if (tokenActual(CatLexica.EQ)) {
			rec(CatLexica.EQ);
			return opComparacionR1();
		} else if (tokenActual(CatLexica.NEQ)) {
			rec(CatLexica.NEQ);
			return opComparacionR2();
		} else if (tokenActual(CatLexica.GT)) {
			rec(CatLexica.GT);
			return opComparacionR3();
		} else if (tokenActual(CatLexica.GE)) {
			rec(CatLexica.GE);
			return opComparacionR4();
		} else if (tokenActual(CatLexica.LT)) {
			rec(CatLexica.LT);
			return opComparacionR5();
		} else if (tokenActual(CatLexica.LE)) {
			rec(CatLexica.LE);
			return opComparacionR6();
		} else {
			errorSintactico(CatLexica.EQ, CatLexica.NEQ, CatLexica.GT,
					CatLexica.GE, CatLexica.LT, CatLexica.LE);
			return null;
		}
	}

	private OpAditivo recOpAditivo() throws IOException {
		if (tokenActual(CatLexica.MAS)) {
			rec(CatLexica.MAS);
			return opAditivoR1();
		} else if (tokenActual(CatLexica.MENOS)) {
			rec(CatLexica.MENOS);
			return opAditivoR2();
		} else if (tokenActual(CatLexica.OR)) {
			rec(CatLexica.OR);
			return opAditivoR3();
		} else {
			errorSintactico(CatLexica.MAS, CatLexica.MENOS, CatLexica.OR);
			return null;
		}
	}

	private OpMultiplicativo recOpMultiplicativo() throws IOException {
		if (tokenActual(CatLexica.POR)) {
			rec(CatLexica.POR);
			return opMultiplicativoR1();
		} else if (tokenActual(CatLexica.DIV)) {
			rec(CatLexica.DIV);
			return opMultiplicativoR2();
		} else if (tokenActual(CatLexica.AND)) {
			rec(CatLexica.AND);
			return opMultiplicativoR3();
		} else {
			errorSintactico(CatLexica.POR, CatLexica.DIV, CatLexica.AND);
			return null;
		}
	}

	private OpUnario recOpUnario() throws IOException {
		if (tokenActual(CatLexica.MENOS)) {
			rec(CatLexica.MENOS);
			return opUnarioR1();
		} else if (tokenActual(CatLexica.NOT)) {
			rec(CatLexica.NOT);
			return opUnarioR2();
		} else {
			errorSintactico(CatLexica.MENOS, CatLexica.NOT);
			return null;
		}
	}

	// -------------------------------------------------
	// CHEQUEO
	// -------------------------------------------------
	private boolean esOpComparacion() {
		return (tokenActual(CatLexica.EQ, CatLexica.NEQ, CatLexica.GT,
				CatLexica.GE, CatLexica.LT, CatLexica.LE));
	}

	private boolean esOpAditivo() {
		return (tokenActual(CatLexica.MAS, CatLexica.MENOS, CatLexica.OR));
	}

	private boolean esOpMultiplicativo() {
		return (tokenActual(CatLexica.POR, CatLexica.DIV, CatLexica.AND));
	}

	private boolean esOpUnario() {
		return (tokenActual(CatLexica.MENOS, CatLexica.NOT));
	}

	// -------------------------------------------------
	// IMPORTANTES
	// -------------------------------------------------

	private void rec(CatLexica c) throws IOException {
		if (tokenActual(c)) {
			tact = analizadorLexico.nextToken();
		} else {
			errorSintactico(c);
		}
	}

	private void errorSintactico(CatLexica... esperadas) {
		System.err.print("(" + tact.getFila() + "," + tact.getCol() + ")"
				+ "ERROR SINTACTICO: Encontrado " + tact
				+ ". Se esperaba alguno de los siguientes elementos: ");
		for (CatLexica catEsperada : esperadas) {
			System.err.print(catEsperada + " ");
		}
		System.err.println();
		System.exit(1);
	}

	private boolean tokenActual(CatLexica... c) {
		boolean encontrada = false;
		int i = 0;
		while (i < c.length && !encontrada) {
			encontrada = tact.getCategoria() == c[i];
			i++;
		}
		return encontrada;
	}

	@SuppressWarnings("unused")
	private Token nextToken() throws IOException {
		return analizadorLexico.nextToken();
	}

	/* Auxiliares */
	
	private Bloque recIdenParaBloque(Tipo tipo, int regla) throws IOException {
		if (tokenActual(CatLexica.IDEN)) {
			Token tIden = tact;
			rec(CatLexica.IDEN);
			Declaraciones decs = null;
			if (regla == 1) {
				decs = recRDeclaraciones(decsR2(decR1(tipo, tIden)));
			} else {
				decs = recRDeclaraciones(decsR2(decR2(tipo, tIden)));
			}
			if (tokenActual(CatLexica.APS)) {
				rec(CatLexica.APS);
				return bloqueR1(decs, recInstrucciones());
			} else {
				errorSintactico(CatLexica.APS);
				return null;
			}
		} else {
			errorSintactico(CatLexica.IDEN);
			return null;
		}
	}
	
	private Declaracion recIdenParaDeclaracion(Tipo tipo, int regla) throws IOException {
		if (tokenActual(CatLexica.IDEN)) {
			Token tIden = tact;
			rec(CatLexica.IDEN);
			if (regla == 1) {
				return decR1(tipo, tIden);
			} else {
				return decR2(tipo, tIden);
			}
		}
		errorSintactico(CatLexica.IDEN);
		return null;
	}
	
	private ParametroFormal recIdenParaParamFormal(Tipo tipo, int regla) throws IOException {
		if (tokenActual(CatLexica.IDEN)) {
			Token tIden = tact;
			rec(CatLexica.IDEN);
			if (regla == 1) {
				return pFormalR1(tipo, tIden);
			} else {
				return pFormalR2(tipo, tIden);
			}
		}
		errorSintactico(CatLexica.IDEN);
		return null;
	}
	
	/* Reglas */
	
	private Programa programaR1(Bloque bloque) {
		if (DEBUG)
			return gramaticaAtributos.new ProgramaR1Debug(bloque);
		else
			return gramaticaAtributos.new ProgramaR1(bloque);
	}

	private Bloque bloqueR1(Declaraciones decs, Instrucciones insts) {
		if (DEBUG)
			return gramaticaAtributos.new BloqueR1Debug(decs, insts);
		else
			return gramaticaAtributos.new BloqueR1(decs, insts);
	}
	
	private Bloque bloqueR2(Instrucciones insts) {
		if (DEBUG)
			return gramaticaAtributos.new BloqueR2Debug(insts);
		else
			return gramaticaAtributos.new BloqueR2(insts);
	}

	private Declaraciones decsR1(Declaraciones decs, Declaracion dec) {
		if (DEBUG)
			return gramaticaAtributos.new DeclaracionesR1Debug(decs, dec);
		else
			return gramaticaAtributos.new DeclaracionesR1(decs, dec);
	}
	
	private Declaraciones decsR2(Declaracion dec) {
		if (DEBUG)
			return gramaticaAtributos.new DeclaracionesR2Debug(dec);
		else
			return gramaticaAtributos.new DeclaracionesR2(dec);
	}

	private Declaracion decR1(Tipo tipo, Token token) {
		if (DEBUG)
			return gramaticaAtributos.new DeclaracionR1Debug(tipo, token);
		else
			return gramaticaAtributos.new DeclaracionR1(tipo, token);
	}
	
	private Declaracion decR2(Tipo tipo, Token token) {
		if (DEBUG)
			return gramaticaAtributos.new DeclaracionR2Debug(tipo, token);
		else
			return gramaticaAtributos.new DeclaracionR2(tipo, token);
	}
	
	private Declaracion decR3(Token token, ParametrosFormales pFormales, Bloque b) {
		if (DEBUG)
			return gramaticaAtributos.new DeclaracionR3Debug(token, pFormales, b);
		else
			return gramaticaAtributos.new DeclaracionR3(token, pFormales, b);
	}

	private Instrucciones instsR1(Instrucciones insts, Instruccion inst) {
		if (DEBUG)
			return gramaticaAtributos.new InstruccionesR1Debug(insts, inst);
		else
			return gramaticaAtributos.new InstruccionesR1(insts, inst);
	}
	
	private Instrucciones instsR2(Instruccion inst) {
		if (DEBUG)
			return gramaticaAtributos.new InstruccionesR2Debug(inst);
		else
			return gramaticaAtributos.new InstruccionesR2(inst);
	}
	
	private Instruccion instR1(IAsignacion iAsignacion) {
		if (DEBUG)
			return gramaticaAtributos.new InstruccionR1Debug(iAsignacion);
		else
			return gramaticaAtributos.new InstruccionR1(iAsignacion);
	}
	
	private Instruccion instR2(INew iNew) {
		if (DEBUG)
			return gramaticaAtributos.new InstruccionR2Debug(iNew);
		else
			return gramaticaAtributos.new InstruccionR2(iNew);
	}
	
	private Instruccion instR3(IDispose iDispose) {
		if (DEBUG)
			return gramaticaAtributos.new InstruccionR3Debug(iDispose);
		else
			return gramaticaAtributos.new InstruccionR3(iDispose);
	}
	
	private Instruccion instR4(IRead iRead) {
		if (DEBUG)
			return gramaticaAtributos.new InstruccionR4Debug(iRead);
		else
			return gramaticaAtributos.new InstruccionR4(iRead);
	}
	
	private Instruccion instR5(IWrite iWrite) {
		if (DEBUG)
			return gramaticaAtributos.new InstruccionR5Debug(iWrite);
		else
			return gramaticaAtributos.new InstruccionR5(iWrite);
	}
	
	private Instruccion instR6(ILlamada iLlamada) {
		if (DEBUG)
			return gramaticaAtributos.new InstruccionR6Debug(iLlamada);
		else
			return gramaticaAtributos.new InstruccionR6(iLlamada);
	}

	private Instruccion instR7(IIf iIf) {
		if (DEBUG)
			return gramaticaAtributos.new InstruccionR7Debug(iIf);
		else
			return gramaticaAtributos.new InstruccionR7(iIf);
	}
	
	private Instruccion instR8(IDo iDo) {
		if (DEBUG)
			return gramaticaAtributos.new InstruccionR8Debug(iDo);
		else
			return gramaticaAtributos.new InstruccionR8(iDo);
	}

	private Tipo tipoR1() {
		if (DEBUG)
			return gramaticaAtributos.new TipoR1Debug();
		else
			return gramaticaAtributos.new TipoR1();
	}

	private Tipo tipoR2() {
		if (DEBUG)
			return gramaticaAtributos.new TipoR2Debug();
		else
			return gramaticaAtributos.new TipoR2();
	}

	private Tipo tipoR3(Tipo t, Token num) {
		if (DEBUG)
			return gramaticaAtributos.new TipoR3Debug(t, num);
		else
			return gramaticaAtributos.new TipoR3(t, num);
	}

	private Tipo tipoR4(Campos campos) {
		if (DEBUG)
			return gramaticaAtributos.new TipoR4Debug(campos);
		else
			return gramaticaAtributos.new TipoR4(campos);
	}
	
	private Tipo tipoR5(Tipo tipo) {
		if (DEBUG)
			return gramaticaAtributos.new TipoR5Debug(tipo);
		else
			return gramaticaAtributos.new TipoR5(tipo);
	}
	
	private Tipo tipoR6(Token token) {
		if (DEBUG)
			return gramaticaAtributos.new TipoR6Debug(token);
		else
			return gramaticaAtributos.new TipoR6(token);
	}
	
	private ParametrosFormales pFormalesR1(ListaParametrosFormales lPF) {
		if (DEBUG)
			return gramaticaAtributos.new ParametrosFormalesR1Debug(lPF);
		else
			return gramaticaAtributos.new ParametrosFormalesR1(lPF);
	}
	
	private ParametrosFormales pFormalesR2() {
		if (DEBUG)
			return gramaticaAtributos.new ParametrosFormalesR2Debug();
		else
			return gramaticaAtributos.new ParametrosFormalesR2();
	}
	
	private ListaParametrosFormales lPFormalesR1(ParametroFormal pF, ListaParametrosFormales lPFs) {
		if (DEBUG)
			return gramaticaAtributos.new ListaParametrosFormalesR1Debug(pF, lPFs);
		else
			return gramaticaAtributos.new ListaParametrosFormalesR1(pF, lPFs);
	}
	
	private ListaParametrosFormales lPFormalesR2(ParametroFormal pF) {
		if (DEBUG)
			return gramaticaAtributos.new ListaParametrosFormalesR2Debug(pF);
		else
			return gramaticaAtributos.new ListaParametrosFormalesR2(pF);
	}
	
	private ParametroFormal pFormalR1(Tipo tipo, Token iden) {
		if (DEBUG)
			return gramaticaAtributos.new ParametroFormalR1Debug(tipo, iden);
		else
			return gramaticaAtributos.new ParametroFormalR1(tipo, iden);
	}
	
	private ParametroFormal pFormalR2(Tipo tipo, Token iden) {
		if (DEBUG)
			return gramaticaAtributos.new ParametroFormalR2Debug(tipo, iden);
		else
			return gramaticaAtributos.new ParametroFormalR2(tipo, iden);
	}
	
	private Campos camposR1(Campos campos, Campo campo) {
		if (DEBUG)
			return gramaticaAtributos.new CamposR1Debug(campos, campo);
		else
			return gramaticaAtributos.new CamposR1(campos, campo);
	}
	
	private Campos camposR2(Campo campo) {
		if (DEBUG)
			return gramaticaAtributos.new CamposR2Debug(campo);
		else
			return gramaticaAtributos.new CamposR2(campo);
	}
	
	private Campo campoR1(Tipo tipo, Token iden) {
		if (DEBUG)
			return gramaticaAtributos.new CampoR1Debug(tipo, iden);
		else
			return gramaticaAtributos.new CampoR1(tipo, iden);
	}
	
	private IAsignacion iAsignacionR1(Mem mem, Exp0 exp) {
		if (DEBUG)
			return gramaticaAtributos.new IAsignacionR1Debug(mem, exp);
		else
			return gramaticaAtributos.new IAsignacionR1(mem, exp);
	}
	
	private INew iNewR1(Mem mem) {
		if (DEBUG)
			return gramaticaAtributos.new INewR1Debug(mem);
		else
			return gramaticaAtributos.new INewR1(mem);
	}
	
	private IDispose iDisposeR1(Mem mem) {
		if (DEBUG)
			return gramaticaAtributos.new IDisposeR1Debug(mem);
		else
			return gramaticaAtributos.new IDisposeR1(mem);
	}
	
	private IRead iReadR1(Mem mem) {
		if (DEBUG)
			return gramaticaAtributos.new IReadR1Debug(mem);
		else
			return gramaticaAtributos.new IReadR1(mem);
	}
	
	private IWrite iWriteR1(Exp0 exp) {
		if (DEBUG)
			return gramaticaAtributos.new IWriteR1Debug(exp);
		else
			return gramaticaAtributos.new IWriteR1(exp);
	}
	
	private ILlamada iLlamadaR1(Token iden, ParametrosReales pR) {
		if (DEBUG)
			return gramaticaAtributos.new ILlamadaR1Debug(iden, pR);
		else
			return gramaticaAtributos.new ILlamadaR1(iden, pR);
	}
	
	private IIf iIfR1(Casos casos) {
		if (DEBUG)
			return gramaticaAtributos.new IIfR1Debug(casos);
		else
			return gramaticaAtributos.new IIfR1(casos);
	}
	
	private IDo iDoR1(Casos casos) {
		if (DEBUG)
			return gramaticaAtributos.new IDoR1Debug(casos);
		else
			return gramaticaAtributos.new IDoR1(casos);
	}
	
	private Casos casosR1(Casos casos, Caso caso) {
		if (DEBUG)
			return gramaticaAtributos.new CasosR1Debug(casos, caso);
		else
			return gramaticaAtributos.new CasosR1(casos, caso);
	}
	
	private Casos casosR2(Caso caso) {
		if (DEBUG)
			return gramaticaAtributos.new CasosR2Debug(caso);
		else
			return gramaticaAtributos.new CasosR2(caso);
	}
	
	private Caso casoR1(Exp0 exp, Instrucciones insts) {
		if (DEBUG)
			return gramaticaAtributos.new CasoR1Debug(exp, insts);
		else
			return gramaticaAtributos.new CasoR1(exp, insts);
	}
	
	private ParametrosReales pRealR1(ListaParametrosReales lPRs) {
		if (DEBUG)
			return gramaticaAtributos.new ParametrosRealesR1Debug(lPRs);
		else
			return gramaticaAtributos.new ParametrosRealesR1(lPRs);
	}
	
	private ParametrosReales pRealR2() {
		if (DEBUG)
			return gramaticaAtributos.new ParametrosRealesR2Debug();
		else
			return gramaticaAtributos.new ParametrosRealesR2();
	}
	
	private ListaParametrosReales lPRealesR1(ListaParametrosReales lPRs, Exp0 exp) {
		if (DEBUG)
			return gramaticaAtributos.new ListaParametrosRealesR1Debug(lPRs, exp);
		else
			return gramaticaAtributos.new ListaParametrosRealesR1(lPRs, exp);
	}
	
	private ListaParametrosReales lPRealesR2(Exp0 exp) {
		if (DEBUG)
			return gramaticaAtributos.new ListaParametrosRealesR2Debug(exp);
		else
			return gramaticaAtributos.new ListaParametrosRealesR2(exp);
	}
	
	private Exp0 exp0R1(OpComparacion op, Exp1 exp10, Exp1 exp11) {
		if (DEBUG)
			return gramaticaAtributos.new Exp0R1Debug(op, exp10, exp11);
		else
			return gramaticaAtributos.new Exp0R1(op, exp10, exp11);
	}
	
	private Exp0 exp0R2(Exp1 exp) {
		if (DEBUG)
			return gramaticaAtributos.new Exp0R2Debug(exp);
		else
			return gramaticaAtributos.new Exp0R2(exp);
	}
	
	private Exp1 exp1R1(OpAditivo op, Exp1 exp1, Exp2 exp2) {
		if (DEBUG)
			return gramaticaAtributos.new Exp1R1Debug(op, exp1, exp2);
		else
			return gramaticaAtributos.new Exp1R1(op, exp1, exp2);
	}
	
	private Exp1 exp1R2(Exp2 exp) {
		if (DEBUG)
			return gramaticaAtributos.new Exp1R2Debug(exp);
		else
			return gramaticaAtributos.new Exp1R2(exp);
	}
	
	private Exp2 exp2R1(OpMultiplicativo op, Exp2 exp2, Exp3 exp3) {
		if (DEBUG)
			return gramaticaAtributos.new Exp2R1Debug(op, exp2, exp3);
		else
			return gramaticaAtributos.new Exp2R1(op, exp2, exp3);
	}
	
	private Exp2 exp2R2(Exp3 exp) {
		if (DEBUG)
			return gramaticaAtributos.new Exp2R2Debug(exp);
		else
			return gramaticaAtributos.new Exp2R2(exp);
	}
	
	private Exp3 exp3R1(OpUnario op, Exp3 exp) {
		if (DEBUG)
			return gramaticaAtributos.new Exp3R1Debug(op, exp);
		else
			return gramaticaAtributos.new Exp3R1(op, exp);
	}
	
	private Exp3 exp3R2(Exp4 exp) {
		if (DEBUG)
			return gramaticaAtributos.new Exp3R2Debug(exp);
		else
			return gramaticaAtributos.new Exp3R2(exp);
	}
	
	private Exp4 exp4R1(Token bool) {
		if (DEBUG)
			return gramaticaAtributos.new Exp4R1Debug(bool);
		else
			return gramaticaAtributos.new Exp4R1(bool);
	}
	
	private Exp4 exp4R2(Token bool) {
		if (DEBUG)
			return gramaticaAtributos.new Exp4R2Debug(bool);
		else
			return gramaticaAtributos.new Exp4R2(bool);
	}
	
	private Exp4 exp4R3(Token num) {
		if (DEBUG)
			return gramaticaAtributos.new Exp4R3Debug(num);
		else
			return gramaticaAtributos.new Exp4R3(num);
	}
	
	private Exp4 exp4R4(Mem mem) {
		if (DEBUG)
			return gramaticaAtributos.new Exp4R4Debug(mem);
		else
			return gramaticaAtributos.new Exp4R4(mem);
	}
	
	private Exp4 exp4R5(Exp0 exp) {
		if (DEBUG)
			return gramaticaAtributos.new Exp4R5Debug(exp);
		else
			return gramaticaAtributos.new Exp4R5(exp);
	}
	
	private Mem memR1(Token iden) {
		if (DEBUG)
			return gramaticaAtributos.new MemR1Debug(iden);
		else
			return gramaticaAtributos.new MemR1(iden);
	}
	
	private Mem memR2(Mem mem, Exp0 exp) {
		if (DEBUG)
			return gramaticaAtributos.new MemR2Debug(mem, exp);
		else
			return gramaticaAtributos.new MemR2(mem, exp);
	}
	
	private Mem memR3(Mem mem, Token iden) {
		if (DEBUG)
			return gramaticaAtributos.new MemR3Debug(mem, iden);
		else
			return gramaticaAtributos.new MemR3(mem, iden);
	}
	
	private Mem memR4(Mem mem) {
		if (DEBUG)
			return gramaticaAtributos.new MemR4Debug(mem);
		else
			return gramaticaAtributos.new MemR4(mem);
	}
	
	private OpComparacion opComparacionR1() {
		if (DEBUG)
			return gramaticaAtributos.new OpComparacionR1Debug();
		else
			return gramaticaAtributos.new OpComparacionR1();
	}
	
	private OpComparacion opComparacionR2() {
		if (DEBUG)
			return gramaticaAtributos.new OpComparacionR2Debug();
		else
			return gramaticaAtributos.new OpComparacionR2();
	}
	
	private OpComparacion opComparacionR3() {
		if (DEBUG)
			return gramaticaAtributos.new OpComparacionR3Debug();
		else
			return gramaticaAtributos.new OpComparacionR3();
	}
	
	private OpComparacion opComparacionR4() {
		if (DEBUG)
			return gramaticaAtributos.new OpComparacionR4Debug();
		else
			return gramaticaAtributos.new OpComparacionR4();
	}
	
	private OpComparacion opComparacionR5() {
		if (DEBUG)
			return gramaticaAtributos.new OpComparacionR5Debug();
		else
			return gramaticaAtributos.new OpComparacionR5();
	}
	
	private OpComparacion opComparacionR6() {
		if (DEBUG)
			return gramaticaAtributos.new OpComparacionR6Debug();
		else
			return gramaticaAtributos.new OpComparacionR6();
	}
	
	private OpAditivo opAditivoR1() {
		if (DEBUG)
			return gramaticaAtributos.new OpAditivoR1Debug();
		else
			return gramaticaAtributos.new OpAditivoR1();
	}
	
	private OpAditivo opAditivoR2() {
		if (DEBUG)
			return gramaticaAtributos.new OpAditivoR2Debug();
		else
			return gramaticaAtributos.new OpAditivoR2();
	}
	
	private OpAditivo opAditivoR3() {
		if (DEBUG)
			return gramaticaAtributos.new OpAditivoR3Debug();
		else
			return gramaticaAtributos.new OpAditivoR3();
	}
	
	private OpMultiplicativo opMultiplicativoR1() {
		if (DEBUG)
			return gramaticaAtributos.new OpMultiplicativoR1Debug();
		else
			return gramaticaAtributos.new OpMultiplicativoR1();
	}
	
	private OpMultiplicativo opMultiplicativoR2() {
		if (DEBUG)
			return gramaticaAtributos.new OpMultiplicativoR2Debug();
		else
			return gramaticaAtributos.new OpMultiplicativoR2();
	}
	
	private OpMultiplicativo opMultiplicativoR3() {
		if (DEBUG)
			return gramaticaAtributos.new OpMultiplicativoR3Debug();
		else
			return gramaticaAtributos.new OpMultiplicativoR3();
	}
	
	private OpUnario opUnarioR1() {
		if (DEBUG)
			return gramaticaAtributos.new OpUnarioR1Debug();
		else
			return gramaticaAtributos.new OpUnarioR1();
	}
	
	private OpUnario opUnarioR2() {
		if (DEBUG)
			return gramaticaAtributos.new OpUnarioR2Debug();
		else
			return gramaticaAtributos.new OpUnarioR2();
	}

}

